#include <iostream>
#include <type_traits>
#include <vector>
#include <list>

// 1. 编译时计算 - 计算斐波那契数列
template <int N>
struct Fibonacci {
    static constexpr long long value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
};

template <>
struct Fibonacci<0> {
    static constexpr long long value = 0;
};

template <>
struct Fibonacci<1> {
    static constexpr long long value = 1;
};

// 2. 编译时类型判断 - 类型特性萃取
template <typename T>
struct is_container : std::false_type {};

template <typename T>
struct is_container<std::vector<T>> : std::true_type {};

template <typename T>
struct is_container<std::list<T>> : std::true_type {};

// 3. SFINAE - 根据类型特性选择不同实现
template <typename T>
typename std::enable_if<is_container<T>::value, void>::type
print_container(const T& container) {
    std::cout << "容器内容: ";
    for (const auto& item : container) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
}

template <typename T>
typename std::enable_if<!is_container<T>::value, void>::type
print_container(const T& value) {
    std::cout << "普通值: " << value << std::endl;
}

// 4. 编译时类型转换和检查
template <typename T>
struct remove_const_ref {
    using type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
};

template <typename T>
using remove_const_ref_t = typename remove_const_ref<T>::type;

// 5. SFINAE检测类型是否有特定成员函数
template <typename T>
class has_size_method {
private:
    template <typename U>
    static auto test(int) -> decltype(std::declval<U>().size(), std::true_type{});

    template <typename U>
    static std::false_type test(...);

public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

// 使用SFINAE根据是否有size()方法选择实现
template <typename T>
typename std::enable_if<has_size_method<T>::value, size_t>::type
get_size(const T& obj) {
    std::cout << "使用size()方法: ";
    return obj.size();
}

template <typename T>
typename std::enable_if<!has_size_method<T>::value, size_t>::type
get_size(const T& obj) {
    std::cout << "使用sizeof: ";
    return sizeof(obj);
}

// 6. 编译时条件判断
template <typename T>
constexpr bool is_numeric = std::is_arithmetic<T>::value && !std::is_same<T, bool>::value;

template <typename T>
typename std::enable_if<is_numeric<T>, T>::type
square(const T& value) {
    return value * value;
}

template <typename T>
typename std::enable_if<!is_numeric<T>, void>::type
square(const T& value) {
    std::cout << "类型 " << typeid(T).name() << " 不支持平方运算" << std::endl;
}

int main() 
{
    // 测试编译时计算
    std::cout << "=== 编译时计算测试 ===" << std::endl;
    std::cout << "Fibonacci(10) = " << Fibonacci<10>::value << std::endl;
    std::cout << "Fibonacci(20) = " << Fibonacci<20>::value << std::endl;

    // 测试类型萃取和SFINAE
    std::cout << "\n=== 类型萃取和SFINAE测试 ===" << std::endl;

    std::vector<int> vec = { 1, 2, 3, 4, 5 };
    std::list<double> lst = { 1.1, 2.2, 3.3 };
    int simple_value = 42;

    print_container(vec);    // 调用容器版本
    print_container(lst);    // 调用容器版本  
    print_container(simple_value); // 调用普通值版本

    // 测试成员函数检测
    std::cout << "\n=== 成员函数检测测试 ===" << std::endl;
    std::cout << "vector大小: " << get_size(vec) << std::endl;
    std::cout << "int大小: " << get_size(simple_value) << std::endl;

    // 测试类型转换
    std::cout << "\n=== 类型转换测试 ===" << std::endl;
    static_assert(std::is_same<remove_const_ref_t<const int&>, int>::value,
        "类型转换失败");
    static_assert(std::is_same<remove_const_ref_t<int>, int>::value,
        "类型转换失败");

    // 测试编译时条件判断
    std::cout << "\n=== 编译时条件测试 ===" << std::endl;
    std::cout << "5的平方: " << square(5) << std::endl;
    std::cout << "3.14的平方: " << square(3.14) << std::endl;
    square("hello"); // 应该输出不支持的消息

    // 编译时断言
    static_assert(Fibonacci<5>::value == 5, "斐波那契计算错误");
    static_assert(is_container<std::vector<int>>::value, "vector应该是容器");
    static_assert(!is_container<int>::value, "int不应该是容器");

    return 0;
}
